package cn.stazxr.deepseekchat.service;

import cn.stazxr.deepseekchat.constants.DeepSeekConstants;
import cn.stazxr.deepseekchat.model.ChatRequest;
import cn.stazxr.deepseekchat.model.Message;
import cn.stazxr.deepseekchat.utils.RequestUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.netty.http.client.PrematureCloseException;
import reactor.util.retry.Retry;

import java.time.Duration;
import java.util.Collections;
import java.util.concurrent.TimeoutException;

/**
 * Service for DeepSeek
 *
 * @author talentestors
 * @version 1.1
 * @since 2025.3.14
 **/
@Slf4j
@Service
public class DeepSeekService {

	private WebClient.Builder webClientBuilder;
	private final ObjectMapper objectMapper = new ObjectMapper();

	public DeepSeekService() {
	}

	@Autowired
	public DeepSeekService(WebClient.Builder webClientBuilder) {
		this.webClientBuilder = webClientBuilder;
	}

	public Flux<String> sendChatRequest(String question) {
		String requestUrl = RequestUtils.getRequestUrl(DeepSeekConstants.CHAT_API);
		ChatRequest request = new ChatRequest();
		Message userMessage = new Message();
		userMessage.setRole("user");
		userMessage.setContent(question);
		request.setMessages(Collections.singletonList(userMessage));

		System.out.println("发送请求到: " + requestUrl);

		return webClientBuilder.build()
			.post()
			.uri(requestUrl)
			.header("Authorization", "Bearer " + RequestUtils.getApiKey())
			.header("Content-Type", "application/json")
			.bodyValue(request)
			.retrieve()
			.bodyToFlux(String.class)
			.timeout(Duration.ofSeconds(90))
			.retryWhen(Retry.backoff(3, Duration.ofSeconds(3))
				.filter(throwable ->
					throwable instanceof PrematureCloseException
					|| throwable instanceof TimeoutException
					|| throwable instanceof RuntimeException)
				.onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> {
					System.out.println("重试次数已用完，最后一次错误: " + retrySignal.failure().getMessage());
					return new RuntimeException("服务暂时不可用，请稍后重试");
				}))
			.onErrorResume(e -> {
				System.out.println("请求处理错误: " + e.getMessage());
				return Flux.just("抱歉，服务器处理请求时发生错误: " + e.getMessage());
			})
			.map(response -> {
				try {
					if ("[DONE]".equals(response)) {
						return "\n";
					}
					JsonNode jsonNode = objectMapper.readTree(response);
					JsonNode choices = jsonNode.get("choices");
					if (choices != null && choices.isArray() && !choices.isEmpty()) {
						JsonNode choice = choices.get(0);
						JsonNode delta = choice.get("delta");
						if (delta != null && delta.has("content")) {
							String content = delta.get("content").asText();
							return content != null ? content : "";
						}
					}
					return "";
				} catch (Exception e) {
					System.out.println("解析响应时出错: " + e.getMessage());
					System.out.println("原始响应: " + response);
					return "";
				}
			}).filter(content -> !content.isEmpty());
	}

	public Flux<String> sendModelListRequest() {
		String requestUrl = RequestUtils.getRequestUrl(DeepSeekConstants.MODEL_LIST_API);
		System.out.println("发送请求到: " + requestUrl);
		return webClientBuilder.build()
			.get()
			.uri(requestUrl)
			.header("Authorization", "Bearer " + RequestUtils.getApiKey())
			.header("Content-Type", "application/json")
			.retrieve()
			.bodyToFlux(String.class)
			.timeout(Duration.ofSeconds(60))
			.retryWhen(Retry.backoff(2, Duration.ofSeconds(2))
				.filter(throwable ->
					throwable instanceof PrematureCloseException
					|| throwable instanceof TimeoutException
					|| throwable instanceof RuntimeException)
				.onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> {
					System.out.println("重试次数已用完，最后一次错误: " + retrySignal.failure().getMessage());
					return new RuntimeException("服务暂时不可用，请稍后重试");
				}))
			.onErrorResume(e -> {
				System.out.println("请求处理错误: " + e.getMessage());
				return Flux.just("抱歉，服务器处理请求时发生错误: " + e.getMessage());
			})
			.map(response -> {
				log.debug(response);
				try {
					JsonNode jsonNode = objectMapper.readTree(response);
					if (jsonNode.has("error")) {
						return "抱歉，服务器处理请求时发生错误: " + jsonNode.get("error").asText();
					}
					return jsonNode.toString();
				} catch (Exception e) {
					log.error("解析响应时发生错误: {}", e.getMessage());
					return e.getMessage();
				}
			});
	}

	public Flux<String> getBalanceInfo() {
		String requestUrl = RequestUtils.getRequestUrl(DeepSeekConstants.BALANCE_API);
		System.out.println("发送请求到: " + requestUrl);
		return webClientBuilder.build()
			.get()
			.uri(requestUrl)
			.header("Authorization", "Bearer " + RequestUtils.getApiKey())
			.header("Content-Type", "application/json")
			.retrieve()
			.bodyToFlux(String.class)
			.timeout(Duration.ofSeconds(30))
			.retryWhen(Retry.backoff(2, Duration.ofSeconds(1))
				.filter(throwable ->
					throwable instanceof PrematureCloseException
					|| throwable instanceof TimeoutException
					|| throwable instanceof RuntimeException)
				.onRetryExhaustedThrow((retryBackoffSpec, retrySignal) -> {
					System.out.println("重试次数已用完，最后一次错误: " + retrySignal.failure().getMessage());
					return new RuntimeException("服务暂时不可用，请稍后重试");
				}))
			.onErrorResume(e -> {
				System.out.println("请求处理错误: " + e.getMessage());
				return Flux.just("抱歉，服务器处理请求时发生错误: " + e.getMessage());
			})
			.map(response -> {
				log.debug(response);
				try {
					JsonNode jsonNode = objectMapper.readTree(response);
					if (!jsonNode.get("is_available").asBoolean()) {
						return "当前账户没有有余额可供 API 调用";
					}
					JsonNode balanceInfos = jsonNode.get("balance_infos");
					return balanceInfos.toString();
				} catch (Exception e) {
					log.error("解析响应时发生错误: {}", e.getMessage());
					return e.getMessage();
				}
			});
	}

}
